/** \file key.c
 **
 ** main file
 **
 ** History:
 **   - 2013-11-03  1.0  Mark  First Version
 *************************************************************************/

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "includes.h"

/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/

/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/
static int gpio_mode[16];

/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/

/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/

void (*GPIOIntCallback)(void);

void (*IntCallbackArray[16])(void);

void GPIO_Init(void)
{
  // initial all IO as input pin
  FM3_GPIO->ADE = 0x000000FF;

  FM3_GPIO->PFR0 &= ~0x8000;
  FM3_GPIO->PFR1 &= ~0xFF00;
  FM3_GPIO->PFR2 &= ~0x01F0;
  FM3_GPIO->PFR4 &= ~0x0300;
  
  FM3_GPIO->DDR0 &= ~0x8000;
  FM3_GPIO->DDR1 &= ~0xFF00;
  FM3_GPIO->DDR2 &= ~0x01F0;
  FM3_GPIO->DDR4 &= ~0x0300;
  
  for (int i=0; i<16; i++)
    gpio_mode[i] = GPIO_INPUT;
  for (int i=0; i<16; i++)
    IntCallbackArray[i] = NULL;
}

void SetIOPort(int IO, int type)
{
  FM3_GPIO->ADE = 0x000000FF;
  if (IO<0 || IO>=16) return;
  
  if (type == GPIO_INPUT) {
    switch(IO){
    case 0 :      FM3_GPIO->PFR0 &= ~0x8000;      FM3_GPIO->DDR0 &= ~0x8000;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 1 :      FM3_GPIO->PFR1 &= ~0x2000;      FM3_GPIO->DDR1 &= ~0x2000;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 2 :      FM3_GPIO->PFR2 &= ~0x0010;      FM3_GPIO->DDR2 &= ~0x0010;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 3 :      FM3_GPIO->PFR1 &= ~0x1000;      FM3_GPIO->DDR1 &= ~0x1000;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 4 :      FM3_GPIO->PFR2 &= ~0x0020;      FM3_GPIO->DDR2 &= ~0x0020;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 5 :      FM3_GPIO->PFR1 &= ~0x0800;      FM3_GPIO->DDR1 &= ~0x0800;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 6 :      FM3_GPIO->PFR2 &= ~0x0040;      FM3_GPIO->DDR2 &= ~0x0040;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 7 :      FM3_GPIO->PFR1 &= ~0x0400;      FM3_GPIO->DDR1 &= ~0x0400;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 8 :      FM3_GPIO->PFR2 &= ~0x0080;      FM3_GPIO->DDR2 &= ~0x0080;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 9 :      FM3_GPIO->PFR1 &= ~0x0200;      FM3_GPIO->DDR1 &= ~0x0200;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 10:      FM3_GPIO->PFR2 &= ~0x0100;      FM3_GPIO->DDR2 &= ~0x0100;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 11:      FM3_GPIO->PFR1 &= ~0x0100;      FM3_GPIO->DDR1 &= ~0x0100;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 12:      FM3_GPIO->PFR1 &= ~0x8000;      FM3_GPIO->DDR1 &= ~0x8000;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 13:      FM3_GPIO->PFR4 &= ~0x0100;      FM3_GPIO->DDR4 &= ~0x0100;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 14:      FM3_GPIO->PFR1 &= ~0x4000;      FM3_GPIO->DDR1 &= ~0x4000;      gpio_mode[IO] = GPIO_INPUT;    break;
    case 15:      FM3_GPIO->PFR4 &= ~0x0200;      FM3_GPIO->DDR4 &= ~0x0200;      gpio_mode[IO] = GPIO_INPUT;    break;
    default:      break;
    }
  }
  if (type == GPIO_OUTPUT) {
    switch(IO){
    case 0 :      FM3_GPIO->PFR0 &= ~0x8000;      FM3_GPIO->DDR0 |= 0x8000;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 1 :      FM3_GPIO->PFR1 &= ~0x2000;      FM3_GPIO->DDR1 |= 0x2000;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 2 :      FM3_GPIO->PFR2 &= ~0x0010;      FM3_GPIO->DDR2 |= 0x0010;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 3 :      FM3_GPIO->PFR1 &= ~0x1000;      FM3_GPIO->DDR1 |= 0x1000;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 4 :      FM3_GPIO->PFR2 &= ~0x0020;      FM3_GPIO->DDR2 |= 0x0020;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 5 :      FM3_GPIO->PFR1 &= ~0x0800;      FM3_GPIO->DDR1 |= 0x0800;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 6 :      FM3_GPIO->PFR2 &= ~0x0040;      FM3_GPIO->DDR2 |= 0x0040;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 7 :      FM3_GPIO->PFR1 &= ~0x0400;      FM3_GPIO->DDR1 |= 0x0400;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 8 :      FM3_GPIO->PFR2 &= ~0x0080;      FM3_GPIO->DDR2 |= 0x0080;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 9 :      FM3_GPIO->PFR1 &= ~0x0200;      FM3_GPIO->DDR1 |= 0x0200;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 10:      FM3_GPIO->PFR2 &= ~0x0100;      FM3_GPIO->DDR2 |= 0x0100;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 11:      FM3_GPIO->PFR1 &= ~0x0100;      FM3_GPIO->DDR1 |= 0x0100;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 12:      FM3_GPIO->PFR1 &= ~0x8000;      FM3_GPIO->DDR1 |= 0x8000;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 13:      FM3_GPIO->PFR4 &= ~0x0100;      FM3_GPIO->DDR4 |= 0x0100;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 14:      FM3_GPIO->PFR1 &= ~0x4000;      FM3_GPIO->DDR1 |= 0x4000;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    case 15:      FM3_GPIO->PFR4 &= ~0x0200;      FM3_GPIO->DDR4 |= 0x0200;      gpio_mode[IO] = GPIO_OUTPUT;    break;
    default:      break;
    }
  }
}

void WriteIOPort(int IO, int value)
{
  if (IO<0 || IO>=16) return;
  
  if (value == 0) value = 0;
  else value = 1;
  
  if (gpio_mode[IO] == GPIO_OUTPUT) {
    switch(IO){
    case 0 :      bFM3_GPIO_PDOR0_PF = value;     break;
    case 1 :      bFM3_GPIO_PDOR1_PD = value;     break;
    case 2 :      bFM3_GPIO_PDOR2_P4 = value;     break;
    case 3 :      bFM3_GPIO_PDOR1_PC = value;     break;
    case 4 :      bFM3_GPIO_PDOR2_P5 = value;     break;
    case 5 :      bFM3_GPIO_PDOR1_PB = value;     break;
    case 6 :      bFM3_GPIO_PDOR2_P6 = value;     break;
    case 7 :      bFM3_GPIO_PDOR1_PA = value;     break;
    case 8 :      bFM3_GPIO_PDOR2_P7 = value;     break;
    case 9 :      bFM3_GPIO_PDOR1_P9 = value;     break;
    case 10:      bFM3_GPIO_PDOR2_P8 = value;     break;
    case 11:      bFM3_GPIO_PDOR1_P8 = value;     break;
    case 12:      bFM3_GPIO_PDOR1_PF = value;     break;
    case 13:      bFM3_GPIO_PDOR4_P8 = value;     break;
    case 14:      bFM3_GPIO_PDOR1_PE = value;     break;
    case 15:      bFM3_GPIO_PDOR4_P9 = value;     break;
    default:      break;
    }
  }
}

int ReadIOPort(int IO)
{
  int ret;
  if (IO<0 || IO>=16) return -1;
  
  if (gpio_mode[IO] == GPIO_INPUT) {
    switch(IO){
    case 0 :      ret = bFM3_GPIO_PDIR0_PF;   break;
    case 1 :      ret = bFM3_GPIO_PDIR1_PD;   break;
    case 2 :      ret = bFM3_GPIO_PDIR2_P4;   break;
    case 3 :      ret = bFM3_GPIO_PDIR1_PC;   break;
    case 4 :      ret = bFM3_GPIO_PDIR2_P5;   break;
    case 5 :      ret = bFM3_GPIO_PDIR1_PB;   break;
    case 6 :      ret = bFM3_GPIO_PDIR2_P6;   break;
    case 7 :      ret = bFM3_GPIO_PDIR1_PA;   break;
    case 8 :      ret = bFM3_GPIO_PDIR2_P7;   break;
    case 9 :      ret = bFM3_GPIO_PDIR1_P9;   break;
    case 10:      ret = bFM3_GPIO_PDIR2_P8;   break;
    case 11:      ret = bFM3_GPIO_PDIR1_P8;   break;
    case 12:      ret = bFM3_GPIO_PDIR1_PF;   break;
    case 13:      ret = bFM3_GPIO_PDIR4_P8;   break;
    case 14:      ret = bFM3_GPIO_PDIR1_PE;   break;
    case 15:      ret = bFM3_GPIO_PDIR4_P9;   break;
    default:      break;
    }
  }
  return ret;
}

boolean_t SetIOInterrupt(uint8_t IO, exint_type_t type, void (*GPIOIntCallback)())
{
  int int_no;
    switch(IO){
    case INT01:
        int_no = 1;
        FM3_GPIO->EPFR06 |= 3<<2;   // use INT01_2
        IntCallbackArray[IO] = GPIOIntCallback;
        break;
    case INT02:
        int_no = 2;
        FM3_GPIO->EPFR06 |= 3<<4;   // use INT02_2
        IntCallbackArray[IO] = GPIOIntCallback;
        break;
    case INT05:
        int_no = 5;
        FM3_GPIO->EPFR06 &= ~(3<<10); // use INT05_1
        FM3_GPIO->EPFR06 |= (2<<10);
        IntCallbackArray[IO] = GPIOIntCallback;
        break;
    case INT14:
        int_no = 14;
        FM3_GPIO->EPFR06 &= ~(3<<28); // use INT14_1
        FM3_GPIO->EPFR06 |= (2<<28);
        IntCallbackArray[IO] = GPIOIntCallback;
        break;
    default:
        return FALSE;
    }
    FM3_EXTI->ENIR &= ~(1<<int_no);       // disable interrupt
    /* set Interrupt Factor Level */
    //if(u8Ch<16)
        FM3_EXTI->ELVR = FM3_EXTI->ELVR & ~(3<<(int_no*2)) | (type<<(int_no*2));
    //else
        //FM3_EXTI->ELVR1 = FM3_EXTI->ELVR & ~(3<<u8Ch) | (type<<u8Ch);
    volatile uint32_t dumm = FM3_EXTI->ELVR;
    FM3_EXTI->EICL  &= ~(1<<int_no);      // clear interrupt factor of INTx pin
    FM3_EXTI->ENIR |= 1<<int_no;          // enable external interrupt

    if(int_no<7){
        NVIC_ClearPendingIRQ(EXINT0_7_IRQn);
        NVIC_EnableIRQ(EXINT0_7_IRQn);
        NVIC_SetPriority(EXINT0_7_IRQn, 7);	// MAX 15
    }
    else{
        NVIC_ClearPendingIRQ(EXINT8_15_IRQn);
        NVIC_EnableIRQ(EXINT8_15_IRQn);
        NVIC_SetPriority(EXINT8_15_IRQn, 7);	// MAX 15
    }
    return TRUE;
}

void  ClearIOInterrupt(uint8_t IO)
{
  int int_no;
    switch(IO){
    case INT01:
        int_no = 1;
        FM3_GPIO->EPFR06 &= ~(3<<2);   // clear INT01
        IntCallbackArray[IO] = NULL;
        break;
    case INT02:
        int_no = 2;
        FM3_GPIO->EPFR06 &= ~(3<<4);   // clear INT02
        IntCallbackArray[IO] = NULL;
        break;
    case INT05:
        int_no = 5;
        FM3_GPIO->EPFR06 &= ~(3<<10) ; // clear INT05
        IntCallbackArray[IO] = NULL;
        break;
    case INT14:
        int_no = 14;
        FM3_GPIO->EPFR06 &= ~(3<<28);  // clear INT14
        IntCallbackArray[IO] = NULL;
        break;
    default:
        return;
    }
    FM3_EXTI->ENIR &= ~(1<<int_no);       // disable interrupt
    FM3_EXTI->EICL  &= ~(1<<int_no);      // clear interrupt factor of INTx pin

    if(int_no<7){
        NVIC_DisableIRQ(EXINT0_7_IRQn);
        NVIC_ClearPendingIRQ(EXINT0_7_IRQn);
    }
    else{
        NVIC_DisableIRQ(EXINT8_15_IRQn);
        NVIC_ClearPendingIRQ(EXINT8_15_IRQn);
    }
}

/* external interrupt response function*/
void INT0_7_Handler(void)
{
    if(bFM3_EXTI_ENIR_EN1 && bFM3_EXTI_EIRR_ER1){     // INT1
        if (IntCallbackArray[INT01] != NULL)
          IntCallbackArray[INT01]();
        bFM3_EXTI_EICL_ECL1 = 0;
    }
    if(bFM3_EXTI_ENIR_EN2 && bFM3_EXTI_EIRR_ER2){      // INT2
        if (IntCallbackArray[INT02] != NULL)
          IntCallbackArray[INT02]();
        bFM3_EXTI_EICL_ECL2 = 0;
    }
    if(bFM3_EXTI_ENIR_EN5 && bFM3_EXTI_EIRR_ER5){     // INT5
        if (IntCallbackArray[INT05] != NULL)
          IntCallbackArray[INT05]();
        bFM3_EXTI_EICL_ECL5 = 0;
    }
}

void INT8_15_Handler(void)
{
    if(bFM3_EXTI_ENIR_EN14 && bFM3_EXTI_EIRR_ER14){   // INT14
        if (IntCallbackArray[INT14] != NULL)
          IntCallbackArray[INT14]();
        bFM3_EXTI_EICL_ECL14 = 0;
    }
}
